﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using UCL.Powersource.Analysis;

namespace UCL.Powersource.Statistics
{
    /// <summary>
    /// This statistic retrieves the number of backlog items with no tests
    /// </summary>
    [Export(typeof(IStatistic))]
    [DataContract(IsReference = true)]
    public class PBIwithNoTests : LinksRelatedWIStatisticsBase
    {
        [ExcludeFromCodeCoverage]
        public override string Label
        {
            get { return "PBI with no tests"; }
        }

        [ExcludeFromCodeCoverage]
        public override string Description
        {
            get { return "Number of Product Backlog Items with no tests in an iteration"; }
        }

        [ExcludeFromCodeCoverage]
        public override string Name
        {
            get { return "PBIwithNoTests"; }
        }

        public static readonly Guid CN_Statistic_Guid = new Guid("836B4995-4FAE-4F56-96E4-FF612C070C31");
        [ExcludeFromCodeCoverage]
        public override Guid Statistic_Guid
        {
            get { return CN_Statistic_Guid; }
        }

       
        private string BacklogsWithDevelopmentTasks { get { return _BacklogsWithDevelopmentTasks; } }

       
        private string TasksWithTests { get { return _TasksWithTests; } }

        string formatted_pbi = "";
        string formatted_tasks = "";
        string formatted_exclpbi = "";
        
        /// <summary>
        /// Class for Invalid work item calculation
        /// </summary>
        /// <param name="collUri">tfs stat project collection Uri</param>
        /// <param name="iteration">Work item iteration</param>
        /// <param name="finishDate">Finish date</param>
        /// <param name="wiStore">Work item store</param>
        /// <returns>Number of invalid work items</returns>
        protected override int? CountInvalidWI(string collUri, string iteration, DateTime finishDate, Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore wiStore)
        {
            if (!collectionCache.ContainsKey(collUri))
            {
                collectionCache.Add(collUri, new Dictionary<string, Dictionary<string, Dictionary<DateTime, WorkItemCollection>>>());
                collectionCache[collUri].Add(iteration, new Dictionary<string, Dictionary<DateTime, WorkItemCollection>>());
                collectionCache[collUri][iteration].Add("AllBacklogsWIthoutTests", new Dictionary<DateTime, WorkItemCollection>());
            }
            else if (!collectionCache[collUri].ContainsKey(iteration))
            {
                collectionCache[collUri].Add(iteration, new Dictionary<string, Dictionary<DateTime, WorkItemCollection>>());
                collectionCache[collUri][iteration].Add("AllBacklogsWIthoutTests", new Dictionary<DateTime, WorkItemCollection>());
            }

            if (!linksCollectionCache.ContainsKey(collUri))
            {
                linksCollectionCache.Add(collUri, new Dictionary<string, Dictionary<string, Dictionary<DateTime, WorkItemLinkInfo[]>>>());
                linksCollectionCache[collUri].Add(iteration, new Dictionary<string, Dictionary<DateTime, WorkItemLinkInfo[]>>());
                linksCollectionCache[collUri][iteration].Add("BacklogsWithDevelopmentTasks", new Dictionary<DateTime, WorkItemLinkInfo[]>());
                linksCollectionCache[collUri][iteration].Add("TasksWithTests", new Dictionary<DateTime, WorkItemLinkInfo[]>());
                linksCollectionCache[collUri][iteration].Add("AllBacklogsWithTests", new Dictionary<DateTime, WorkItemLinkInfo[]>());
            }
            else if (!linksCollectionCache[collUri].ContainsKey(iteration))
            {
                linksCollectionCache[collUri].Add(iteration, new Dictionary<string, Dictionary<DateTime, WorkItemLinkInfo[]>>());
                linksCollectionCache[collUri][iteration].Add("BacklogsWithDevelopmentTasks", new Dictionary<DateTime, WorkItemLinkInfo[]>());
                linksCollectionCache[collUri][iteration].Add("TasksWithTests", new Dictionary<DateTime, WorkItemLinkInfo[]>());
                linksCollectionCache[collUri][iteration].Add("AllBacklogsWithTests", new Dictionary<DateTime, WorkItemLinkInfo[]>());
            }

            List<int> wiList = new List<int>();
            List<int> temp = new List<int>();

            queryLinkResults = GetQueryLinkResults(BacklogsWithDevelopmentTasks, collUri, finishDate, iteration, wiStore, "BacklogsWithDevelopmentTasks");
            temp.AddRange(GetListOfIds(true, true, wiStore, iteration));

            formatted_pbi = StatisticsUtilities.Format(temp);
            temp.Clear();

            queryLinkResults = GetQueryLinkResults(TasksWithTests, collUri, finishDate,iteration, wiStore, "TasksWithTests");
            temp.AddRange(GetListOfIds(false, true, wiStore, iteration));

            formatted_tasks = StatisticsUtilities.Format(temp);
            temp.Clear();

            queryLinkResults = GetQueryLinkResults(AllBacklogsWithTests, collUri, finishDate,iteration , wiStore, "AllBacklogsWithTests");
            temp.AddRange(GetListOfIds(true, true, wiStore, iteration));

            formatted_exclpbi = StatisticsUtilities.Format(temp);

            queryResults = GetQueryResults(AllBacklogsWIthoutTests, collUri, finishDate, iteration , wiStore, "AllBacklogsWIthoutTests");
            wiList.AddRange(GetListOfIds(true, false, wiStore, iteration));

            return wiList.Select(p => p).Distinct().Count();
        }
    
        // Query to find Back Log items with at least one development task
        [DataMember]
        private readonly string _BacklogsWithDevelopmentTasks =        
                "SELECT [Id] " +
                "FROM WorkItemLinks " +
                "WHERE ([Source].[System.WorkItemType] = 'Product Backlog Item'  " +
                "AND  [Source].[State] <> 'Removed') " +
                "And ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward') " +
                "And ([Target].[System.WorkItemType] = 'Task'  " +
                "AND  [Target].[Microsoft.VSTS.Common.Activity] = 'Development') " +
                "mode(MustContain) AsOf @AsOf";

        // Query to find Tasks that have test cases assigned
        [DataMember]
        private readonly string _TasksWithTests =
                "SELECT [Id] " +
                "FROM WorkItemLinks " +
                "WHERE ([Source].[System.WorkItemType] = 'Task'  " +
                "AND  [Source].[State] <> 'Removed') " +
                "And ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward') " +
                "And ([Target].[System.WorkItemType] = 'Test Case') " +
                "mode(MustContain) AsOf @AsOf";

     
        // Query to find FILTERED Backlog items with test cases directly assigned
        // or with tasks that in turn are related to test cases
        private string AllBacklogsWithTests 
        {  
            get { 
            return          
                "SELECT [Id] FROM WorkItemLinks " +
                "WHERE ([Source].[System.WorkItemType] = 'Product Backlog Item'  " +
                "AND  [Source].[State] <> 'Removed'  AND  [Source].[Id] IN (" + formatted_pbi + ")) " +
                "And ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward' " +
                "OR   [System.Links.LinkType] = 'Microsoft.VSTS.Common.TestedBy-Forward') " +
                "And (([Target].[System.WorkItemType] = 'Task' AND [Target].[Id] IN (" + formatted_tasks + "))" +
                "OR ([Target].[System.WorkItemType] = 'Test Case'))" +
                "mode(MustContain) AsOf @AsOf";
                } 
        }

        // Gets the Backlog items that DO NOT have a test
        // related, row0Index.e. the counterpart of the group of backlogs 
        // got in the previous query
        [DataMember]
        private readonly string _AllBacklogsWIthoutTests =
                    "SELECT [Id], [Iteration Path] " +
                    "FROM WorkItem " +
                    "WHERE ([Work Item Type] = 'Product Backlog Item'  AND  " +
                    "[State] = 'Done')";

        private string AllBacklogsWIthoutTests 
        {
            get { return _AllBacklogsWIthoutTests + "AND ([Id] IN (" + formatted_pbi + ")  AND [Id] NOT IN (" + formatted_exclpbi +
                ")) AsOf @AsOf "; }
        }
    
    }
}
